"""
Case Type   : 操作系统类-文件系统故障
Case Name   : 并发连接时注入故障文件句柄耗尽
Create At   : 2021/7/23
Owner       : @peilinqian
Description :
    1、启多线程连接数据库
    2、主节点注入60s句柄耗尽故障
    3、步骤1结果验证
    4、故障结束后，再次启多线程连接数据库
Expect      :
    1、开始启多线程成功
    2、故障注入成功
    3、步骤1结果验证，报错“Too many open files”
    4、故障结束后，再次启多线程连接数据库成功
History     :
    Modified by @peilinqian 2021/8/23: 优化故障清理
    Modified by @peilinqian 2021/12/9: 优化故障清理后重启数据库
    Modified by @peilinqian 2024/2/21: 优化用例删除不必要步骤
    Modified by @peilinqian 2024/7/9： 优化用例，增加清理等待时间
"""
import os
import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.CommonSH import RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node


class ReliabilityFileSystem(unittest.TestCase):
    nodes = ("PrimaryDbUser", "Standby1DbUser", "Standby2DbUser")

    @RestartDbCluster(*nodes)
    def setUp(self):
        self.log = Logger()
        self.pri_sh = CommonSH(self.nodes[0])
        self.sta_1_sh = CommonSH(self.nodes[1])
        self.sta_2_sh = CommonSH(self.nodes[2])
        self.pri_root = Node(node="PrimaryRoot")
        self.constant = Constant()
        self.com = Common()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.inject_time = 60
        self.inject_cmd = f"rfile_deplenish (timeout) values " \
                          f"({self.inject_time})"
        self.check_cmd = "df -h"

    def test_main(self):
        try:
            self.step1_txt = '----step1:启多线程连接数据库; expect:开始执行----'
            self.log.info(self.step1_txt)
            connect_thread = []
            sql = "select pg_sleep(20);select count(*) from pg_class;" \
                  "select pg_sleep(20)"
            for i in range(9):
                connect_thread.append(ComThread(self.pri_sh.executDbSql,
                                                args=(sql,)))
                connect_thread[i].setDaemon(True)
                connect_thread[i].start()

            time.sleep(5)

            self.step2_txt = '----step2:主节点注入60s句柄耗尽故障; expect:成功----'
            self.log.info(self.step2_txt)
            self.session = ComThread(self.com.cfe_inject,
                                     args=(self.pri_root,
                                           self.inject_cmd))
            self.session.setDaemon(True)
            self.session.start()
            self.start_time = time.time()

            self.step1_txt = '----step3:步骤1连接数据库结果验证; ' \
                             'expect:报错“Too many open files”----'
            self.log.info(self.step1_txt)
            for i in range(9):
                connect_thread[i].join(60)
                result = connect_thread[i].get_result()
                self.log.info(result)
                self.assertIn('Too many open files', result,
                              "执行失败" + self.step2_txt)

        finally:
            self.log.info("-----注入故障结果-----")
            self.session.join(60)
            result = self.session.get_result()
            self.log.info(result)
            self.assertIn(self.constant.SUCCESS_CFE_FULL_FILENUM_MSG, result,
                          "执行失败" + self.step2_txt)
            text = "-----确认故障清理干净-----"
            self.log.info(text)
            while True:
                time.sleep(5)
                check_msg = self.pri_root.sh(self.check_cmd).result()
                self.log.info(check_msg)
                if self.constant.TOO_MANYY_FILE_MSG not in check_msg:
                    break
                end_time = time.time()
                if end_time - self.start_time > self.inject_time * 10:
                    break

            step_txt = '----集群状态异常时，恢复环境----'
            self.log.info(step_txt)
            status = self.pri_sh.getDbClusterStatus("status")
            if not status:
                self.result = self.pri_sh.startDbCluster()
                self.final_status = self.pri_sh.getDbClusterStatus("status")

            step_txt = '----step4:再次启多线程连接数据库; expect:成功----'
            self.log.info(step_txt)
            connect_thread = []
            sql = "select pg_sleep(20);select count(*) from pg_class;" \
                  "select pg_sleep(20)"
            for i in range(9):
                connect_thread.append(ComThread(self.pri_sh.executDbSql,
                                                args=(sql,)))
                connect_thread[i].setDaemon(True)
                connect_thread[i].start()
            for i in range(9):
                connect_thread[i].join(60)
                result = connect_thread[i].get_result()
                self.log.info(result)
                self.assertEqual(result.count('1 row'), 3,
                                 "执行失败" + step_txt)

    def tearDown(self):
        self.log.info("----this is tearDown----")
        step_txt = '----集群状态异常时，恢复环境----'
        self.log.info(step_txt)
        status = self.pri_sh.getDbClusterStatus("status")
        if not status:
            self.result = self.pri_sh.startDbCluster()
            self.final_status = self.pri_sh.getDbClusterStatus("status")

        self.log.info(f'-----{os.path.basename(__file__)} end-----')
        if not status:
            self.assertTrue(self.final_status, "执行失败" + step_txt)
